package com.jigoucai.service.impl;

import com.jigoucai.bean.param.biz.MLogin;
import com.jigoucai.bean.param.req.user.MLoginReq;
import com.jigoucai.entity.user.*;
import com.jigoucai.service.FinanceService;
import com.jigoucai.service.JedisService;
import com.jigoucai.service.UserService;
import com.jigoucai.util.JgcUtil;
import com.jigoucai.util.Util;
import org.nutz.dao.Cnd;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.Times;
import org.nutz.lang.random.R;
import org.nutz.mvc.Mvcs;
import org.nutz.weixin.bean.sns.req.Jscode2sessionReq;
import org.nutz.weixin.bean.sns.resp.Jscode2sessionResp;
import org.nutz.weixin.util.sns.MiniappUtil;

import javax.servlet.http.HttpServletRequest;
import java.util.Set;

/**
 * Created on 2018/3/17
 *
 * @author Jianghao(howechiang @ gmail.com)
 */
@IocBean
public class UserServiceImpl extends BaseServiceImpl implements UserService {

    @Inject("java:$conf.get('weixin.miniapp.appid')")
    protected String WEIXIN_MINIAPP_APPID;
    @Inject("java:$conf.get('weixin.miniapp.appsecret')")
    protected String WEIXIN_MINIAPP_APPSECRET;

    @Override
    public Account fetch(String source, String openId) {
        Account account = dao.fetch(Account.class, Cnd.where("openId", "=", openId).and("source", "=", source));
        if (Lang.isEmpty(account))
            return null;
        else
            return dao.fetchLinks(account, null);
    }

    @Override
    public User fetch(Integer userId) {
        User user = dao.fetch(User.class, userId);
        if (Lang.isEmpty(user))
            return null;
        else {
            user.setNickName(Util.Base64.decode(user.getNickName()));
            return dao.fetchLinks(user, null);
        }
    }

    @Override
    public MLogin mLogin(MLoginReq req, HttpServletRequest request) {

        Jscode2sessionResp resp = MiniappUtil.jscode2session(new Jscode2sessionReq(WEIXIN_MINIAPP_APPID,
                WEIXIN_MINIAPP_APPSECRET, req.getCode(), "authorization_code"));

        req.getRawData().setNickName(Strings.isBlank(req.getRawData().getNickName()) ? "5Lu7546p55So5oi3" : Util.Base64.encode(req.getRawData().getNickName()));
        Account account = fetch(req.getSource(), resp.getOpenid());
        if (Lang.isEmpty(account)) {
            User user = new User();
            user.setPassword("");
            user.setSalt("");
            user.setAuth(false);
            user.setLock(false);
            user.setRealname("");
            user.setMobile("");
            user.setIdCard("");
            user.setAvatarUrl(Strings.isBlank(req.getRawData().getAvatarUrl()) ? "https://static.dianjingpai.com/images/dianjingshe/avatar/1.png" : req.getRawData().getAvatarUrl());
            user.setNickName(req.getRawData().getNickName());
            user.setUsername(JgcUtil.generateUsername("JY"));
            LoginLog loginLog = new LoginLog();
            loginLog.setAppFrom(req.getApp().getAppName() + "|" + req.getApp().getAppVersion());
            loginLog.setDevice(req.getDevice());
            loginLog.setUserId(user.getUserId());
            loginLog.setSource(req.getSource().toUpperCase());
            loginLog.setLoginTime(Times.now());
            loginLog.setLoginIp(Lang.getIP(request));
            loginLog.setLoginAgent(Util.getAgent(request));
            user.setLastLoginLog(loginLog);
            dao.insert(user);
            loginLog.setUserId(user.getUserId());
            dao.insert(loginLog);
            account = new Account();
            account.setUserId(user.getUserId());
            account.setLastLoginLog(loginLog);
            account.setOpenId(resp.getOpenid());
            account.setBindTime(Times.now());
            account.setAccessToken(resp.getSession_key());
            account.setTokenCreateTime(Times.now());
            account.setTokenExpireTime(Times.nextDay(Times.now(), 1));
            account.setExpand(Lang.obj2nutmap(resp));
            account.setSource(req.getSource());
            dao.insert(account);
            RegLog reg = new RegLog();
            reg.setAppFrom(req.getApp().getAppName() + "|" + req.getApp().getAppVersion());
            reg.setDevice(req.getDevice());
            reg.setSource(req.getSource().toUpperCase());
            reg.setRegIp(Lang.getIP(Mvcs.getReq()));
            reg.setRegTime(Times.now());
            reg.setSource(reg.getSource());
            reg.setRegAgent(Util.getAgent(Mvcs.getReq()));
            if (Lang.isEmpty(req.getApp()) || Strings.isBlank(req.getApp().getChannel())) {
                reg.setChannel("jinyou");
                reg.setPromoCode("20000001");
            } else {
                reg.setChannel(Strings.split(req.getApp().getChannel(), false, '|')[0]);
                reg.setPromoCode(Strings.split(req.getApp().getChannel(), false, '|')[1]);
            }
            reg.setUserId(user.getUserId());
            dao.insert(reg);
            Token token = new Token();
            token.setUserId(user.getUserId());
            token.setCreateTime(Times.now());
            token.setFailureTime(Times.nextDay(Times.now(), 2));
            token.setAccessToken(Lang.md5(user.getUserId() + Times.getNowSDT() + R.UU32()));
            dao.insert(token);
            Set<String> set = JedisService.keys("user:token:" + user.getUserId() + ":*");
            set.stream().forEach(s -> {
                JedisService.del(s);
            });
            JedisService.set("user:token:" + user.getUserId() + ":" + token.getAccessToken(), Json.toJson(token, JsonFormat.compact()), 86400);
            MLogin login = new MLogin();
            login.setAuth(false);
            login.setFailureTime(Times.d2TS(token.getFailureTime()));
            login.setMobile("");
            login.setNickname(Util.Base64.decode(user.getNickName()));
            login.setUsername(user.getUsername());
            login.setAvatarUrl(user.getAvatarUrl());
            login.setToken(token.getAccessToken());
            login.setMyFund(0.00);
            login.setUserId(user.getUserId());
            login.setMyMargin(0.00);
            return login;
        } else {
            User user = fetch(account.getUserId());
            LoginLog loginLog = new LoginLog();
            loginLog.setAppFrom(req.getApp().getAppName() + "|" + req.getApp().getAppVersion());
            loginLog.setDevice(req.getDevice());
            loginLog.setUserId(user.getUserId());
            loginLog.setSource(req.getSource().toUpperCase());
            loginLog.setLoginTime(Times.now());
            loginLog.setLoginIp(Lang.getIP(request));
            loginLog.setLoginAgent(Util.getAgent(request));
            dao.insert(loginLog);
            user.setAvatarUrl(req.getRawData().getAvatarUrl());
            user.setNickName(req.getRawData().getNickName());
            user.setLastLoginLog(loginLog);
            dao.update(user, "^(lastLoginLog|avatarUrl|nickName)$");
            account.setLastLoginLog(loginLog);
            account.setTokenCreateTime(Times.now());
            account.setTokenExpireTime(Times.nextDay(Times.now(), 2));
            account.setAccessToken(resp.getSession_key());
            dao.update(account, "^(lastLoginLog|tokenCreateTime|tokenExpireTime|accessToken)$");
            Token token = fetchToken(user.getUserId());
            if (Lang.isEmpty(token)) {
                token = new Token();
                token.setUserId(user.getUserId());
                token.setCreateTime(Times.now());
            }
            token.setFailureTime(Times.nextDay(Times.now(), 1));
            token.setAccessToken(Lang.md5(user.getUserId() + Times.getNowSDT() + R.UU32()));
            dao.insertOrUpdate(token);
            Set<String> set = JedisService.keys("user:token:" + user.getUserId() + ":*");
            set.stream().forEach(s -> {
                JedisService.del(s);
            });
            JedisService.set("user:token:" + user.getUserId() + ":" + token.getAccessToken(), Json.toJson(token, JsonFormat.compact()), 86400);
            MLogin login = new MLogin();
            login.setAuth(false);
            login.setFailureTime(Times.d2TS(token.getFailureTime()));
            login.setMobile(user.getMobile());
            login.setNickname(Util.Base64.decode(user.getNickName()));
            login.setUsername(user.getUsername());
            login.setAvatarUrl(user.getAvatarUrl());
            login.setToken(token.getAccessToken());
            login.setMyFund(financeService.getFund(user.getUserId()));
            login.setUserId(user.getUserId());
            login.setMyMargin(financeService.getMargin(user.getUserId()));
            return login;
        }
    }

    @Override
    public Token fetchToken(Integer userId) {
        return dao.fetch(Token.class, userId);
    }

    @Inject
    FinanceService financeService;
}
